<?php


namespace app\common\cachemodel\zlcr2;


use app\common\cachemodel\AppBlacklist;
use app\common\cachemodel\Goods;
use app\common\cachemodel\Orders;
use app\common\cachemodel\ZlcrAstr;
use app\common\cachemodel\ZlcrAstrMessage;
use app\common\cachemodel\ZlUserVip;
use app\common\lib\Util;
use app\common\lib\exception\ApiException;
use app\common\model\BaseCache;
use app\common\model\Recode;
use app\common\model\User;
use think\Cache;
use think\Log;
use traits\model\SoftDelete;
use XznsTools\cache\CacheManage;

class Zlcr2UserQuestion extends BaseCache
{
    protected $table = 'wechat_backup_07_18_14_43_00.zlcr2_user_question';

    protected $cacheModel = 'question_answer.question';

    protected $isDelUserReadQuestionRecord = false;

    use SoftDelete;

    /**
     * 根据问题的类型，返回文字和语音的最大最小输入配置
     * @param $question_type 1：星盘；2：骰子；3：塔罗；
     * @return int[]|void
     */
    public function answerRule($question_type)
    {
        $questionGoods = config('zlcr2_question.info');

        switch ($question_type)
        {
            case 1:
                return [  // 星盘
                    'text_min' => $questionGoods[77]['text_min'] ?? 240,
                    'text_max' => $questionGoods[77]['text_max'] ?? 400,
                    'duration_min' => Util::isOnline() ? $questionGoods[77]['duration_min'] : 12,
                    'duration_max' => $questionGoods[77]['duration_max'] ?? 300,
                ];
            case 2:
                return [  // 骰子
                    'text_min' => $questionGoods[79]['text_min'] ?? 50,
                    'text_max' => $questionGoods[79]['text_max'] ?? 240,
                    'duration_min' => Util::isOnline() ? $questionGoods[79]['duration_min'] : 6,
                    'duration_max' => $questionGoods[79]['duration_max'] ?? 300,
                ];
            case 3:
                return [  // 塔罗
                    'text_min' => $questionGoods[78]['text_min'] ?? 180,
                    'text_max' => $questionGoods[78]['text_max'] ?? 300,
                    'duration_min' => Util::isOnline() ? $questionGoods[78]['duration_min'] : 12,
                    'duration_max' => $questionGoods[78]['duration_max'] ?? 300,
                ];
        }
    }

    /**
     * 用户问答下单处理
     * @param $type 1=>下单 2=>回调
     * @param $order_id
     * @return bool
     * @throws ApiException
     */
    public function orderQuestion($type, $order_id)
    {
        $orders = current((new Orders())->batchGetInfo([$order_id], ['fid', 'extend', 'uid', 'gid']));
        $history = json_decode($orders['extend'], true);
        $nowTime = time();
        $res = $this->getQuestionType((int)$orders['gid']);
        //获取订单活动信息
        if (isset($history['new_active']))
        {
            $activityDiscount = $history['new_active'][$orders['gid']]['attr'] ?? 1;
        }
        //问题处理
        if ($res['type'] === 3)
        {
            if ($type === 1)
            {
                $questionData = ['order_num' => $order_id, 'status' => 1, 'activity_discount' => $activityDiscount ?? 1, 'uid' => $orders['uid']];
            } else
            {
                $questionData = ['status' => 2, 'consult_time' => $nowTime, 'pay_time' => $nowTime];
            }
            //问题
            $this->UpdateData($orders['fid'], $questionData);
            return 0;
        }

        //追问处理
        if ($res['type'] === 2)
        {
            $addModel = new Zlcr2UserAddQuestion();
            if ($type === 1)
            {
                $addQuestion = Cache::get('question_answer:add_question:' . $orders['fid'], false);
                if ($addQuestion === false)
                {
                    throw new ApiException('服务异常,请稍后再试!');
                }
                //追问
                $addData = [
                    'qid' => $orders['fid'],
                    'status' => 1,
                    'order_num' => $order_id,
                    'question' => $addQuestion['content'],
                    'create_time' => $nowTime,
                    'pay_time' => 0,
                    'answer_content' => '',
                    'answer_duration' => 0,
                    'activity_discount' => $activityDiscount ?? 1,
                    'reply_time' => 0,
                    'reply_type' => 0,
                    'reply_uid' => 0,
                ];
                return $addModel->SaveData($orders['fid'], $addData);
            }
            $addModel->UpdateData($orders['fid'], $history['history']['id'], ['status' => 2, 'pay_time' => $nowTime]);
            // 问题状态更新至 追问待解答
            $this->UpdateData($orders['fid'], ['status' => 8]);
            $questionInfo = $this->getInfoById($orders['fid'], ['astr_id']);
            // 给占星师发送短信
            $hour = (int)(date('H'));
            if ($hour >= 8 && $hour < 21)
            {   // 白天
                $msgContent = "你的任务{$orders['fid']}有新的追问，请在3小时内给出回复，超时将受到惩罚。";
                $tpId = 52342;
                $timeStr = '3';
            } else
            {   // 晚上
                $timeStr = $hour >= 21 ? '在次日11' : '在11';
                $msgContent = "你的任务{$orders['fid']}有新的追问，请{$timeStr}点前回复，超时将受到惩罚。";
                $tpId = 52343;
            }

            $tel = (new ZlcrAstr())->getInfoById($questionInfo['astr_id'], ['tel']);
            Util::sendHySms([$tel['tel']], '', $tpId, ['task_id' => $orders['fid'], 'time' => $timeStr]);

            // 发送占星师站内信
            (new ZlcrAstrMessage())->add($questionInfo['astr_id'], [
                'status' => 0,
                'is_read' => 0,
                'astr_id' => $questionInfo['astr_id'],
                'type' => 0, // 占星师违规消息
                'title' => '追问提示',
                'content' => $msgContent,
                'target' => '',
                'link' => '',
                'create_time' => $nowTime,
            ]);
            if ($tpId === 52342)
            {   // 白天   追问1小时是否回复检测 未回复发送消息提醒
                Util::queuePush('question_answer_add_question_reply_notify_check', ['add_question_id' => $history['history']['id'], 'astr_id' => $questionInfo['astr_id']], 3600);
            }
            // 追问回复超时 检测
            Util::queuePush('question_answer_add_question_reply_timeout_check', ['add_question_id' => $history['history']['id']], Util::getToAnswerTime($nowTime));
            return 0;
        }

        //蹭看处理
        if ($res['type'] === 1)
        {
            $qids = (new Zlcr2QuestionUserView())->getListPage($orders['uid']);
            if (in_array($orders['fid'], $qids, false))
            {
                throw new ApiException('已经蹭看过了');
            }
            if ($type === 2)
            {
                //蹭看
                $viewData = [
                    'uid' => $orders['uid'],
                    'qid' => $orders['fid'],
                    'order_num' => $order_id,
                    'create_time' => time(),
                    'status' => 1,
                ];
                (new Zlcr2QuestionUserView())->SaveData($viewData);
                $questionInfo = $this->getInfoById($orders['fid'], ['look_num']);
                $this->UpdateData($orders['fid'], ['look_num' => $questionInfo['look_num'] + 1]);
            }
            return 0;
        }
        throw new ApiException('商品不存在');
    }

    /**
     * 获取问题类型
     * @param int $gid
     * @return array
     * @throws ApiException
     */
    public function getQuestionType(int $gid)
    {
        $questionGoods = config('zlcr2_question');
        $addGids = array_values($questionGoods['add_question']);
        $lookGids = $questionGoods['look_gid'];
        $data = [];
        //蹭看处理
        if ($gid === $lookGids)
        {
            $data['type'] = 1;
        } //追问处理
        elseif (in_array($gid, $addGids, true))
        {
            $data['type'] = 2;
            $addQuestionGoods = array_flip($questionGoods['add_question']);
            $questionGid = $addQuestionGoods[$gid];
            switch ($questionGoods['info'][$questionGid]['type'])
            {
                case 1:
                    $data['sec'] = 1;//星盘
                    break;
                case 2:
                    $data['sec'] = 2;//骰子
                    break;
                case 3:
                    $data['sec'] = 3;//塔罗
                    break;
            }
        }//问答处理
        elseif (isset($questionGoods['info'][$gid]['type']))
        {
            $data['type'] = 3;
            switch ($questionGoods['info'][$gid]['type'])
            {
                case 1:
                    $data['sec'] = 1;//星盘
                    break;
                case 2:
                    $data['sec'] = 2;//骰子
                    break;
                case 3:
                    $data['sec'] = 3;//塔罗
                    break;
            }
        } else
        {
            Log::write('问题类型异常,商品ID：' . $gid, 'error', true);
            throw new ApiException('问题类型异常');
        }
        return $data;
    }

    /**
     * 新增问答信息
     */
    public function SaveData($uid, $data)
    {
        try
        {
            $this->insert($data);
            // 免费问题添加至我的问答-提问列表
            if (!$data['question_type'])
            {
                $this->listDataAdd($uid, [$data['id'] => $data['id']]);
            }

            if ($data['status'] === 6)
            {   // 免费  已完成
                // 添加至时间排序列表
                CacheManage::getInstance()->setCacheConfig($this->cacheModel)->listAdd([$data['id'] => $data['consult_time']], 0, 'time_sort');
                // 添加至推荐值排序列表
                CacheManage::getInstance()->setCacheConfig($this->cacheModel)->listAdd([$data['id'] => 0], 0, 'recommended_sort');
            }

            return true;
        }
        catch (\Exception $e)
        {
            Log::write('问答 Zlcr2UserQuestion model => SaveData()异常：' . $e->getMessage() . '失败行数：' . $e->getLine(), 'error');
            return false;
        }
    }

    /**
     * 更新问答信息
     */
    public function UpdateData($qid, $data)
    {
        try
        {
            $uid = $data['uid'] ?? 0;
            unset($data['uid']);

            $this::withTrashed()->where(['id' => (string)$qid])->update($data);

            if (isset($data['status']))
            {
                if ($data['status'] === 2)
                {
                    $questionIsHide = $this::withTrashed()->where(['id' => (string)$qid])->value('is_hide');
                    if ($questionIsHide == 0)
                    {
                        // 添加至时间排序列表
                        CacheManage::getInstance()->setCacheConfig($this->cacheModel)->listAdd([$qid => $data['consult_time']], 0, 'time_sort');
                        // 添加至推荐值排序列表
                        CacheManage::getInstance()->setCacheConfig($this->cacheModel)->listAdd([$qid => 0], 0, 'recommended_sort');
                    }
                    // 添加至待接单列表
                    // CacheManage::getInstance()->setCacheConfig($this->cacheModel)->listAdd([$qid => $data['consult_time']], 0, 'waiting_list');
                    // $this->questionWaitingListAdd([$qid => $data['consult_time']]);
                    // 添加8小时未接单 取消订单 检测的队列
                    Util::queuePush('question_answer_astr_receiving_check', [
                        'qid' => $qid,
                    ], 28800);
                }

                if (in_array($data['status'], [10, 11], true))
                {   // 无人接单 订单取消
                    // 至时间排序列表 删除
                    $this->listDataDel(0, [$qid], 0, 'time_sort');
                    // 至推荐值排序列表 删除
                    $this->listDataDel(0, [$qid], 0, 'recommended_sort');
                }
            }
            if (isset($data['order_num']))
            {
                $this->listDataAdd($uid, [$qid => $qid]);
            }
            if (isset($data['is_read']))
            {
                if ($data['is_read'] === 1)
                {
                    CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('unread_question', $uid)->delJudge($qid, 'unread_question');
                } else
                {
                    CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('unread_question', $uid)->listAdd([$qid => $qid], 0, 'unread_question');
                }
            }
            //我的问答列表缓存
            if (isset($data['delete_time']))
            {
                $this->listDataDel($uid, [$qid]);
                CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('unread_question', $uid)->delJudge($qid, 'unread_question');
                // 至时间排序列表 删除
                $this->listDataDel(0, [$qid], 0, 'time_sort');
                // 至推荐值排序列表 删除
                $this->listDataDel(0, [$qid], 0, 'recommended_sort');
            }

            CacheManage::getInstance()->setCacheConfig($this->cacheModel, $qid)->setCache($data);

            return true;
        }
        catch (\Exception $e)
        {
            Log::write('问答 Zlcr2UserQuestion model => UpdateData()异常：' . $e->getMessage() . '失败行数：' . $e->getLine(), 'error');
            return false;
        }
    }

    /**
     * 接单列表添加
     * @param array $data [id=>排序]
     * @throws \Exception
     */
    public function questionWaitingListAdd(array $data)
    {
        $cacheModel = CacheManage::getInstance()->setCacheConfig($this->cacheModel);
        $redis = $cacheModel->redisHandler;
        $cacheKey = $cacheModel->cacheKey['waiting_list'];

        if ($redis->exists($cacheKey))
        {   // 缓存存在
            $pipe = $redis->multi($redis::PIPELINE);
            foreach ($data as $id => $sort)
            {
                $pipe->zAdd($cacheKey, [], $sort, $id);
            }
            $pipe->exec();
        } else
        {   // 缓存丢失
            $questionData = $this->where(['status' => 2])->column('consult_time', 'id');
            $pipe = $redis->multi($redis::PIPELINE);
            $pipe->zAdd($cacheKey, [], 0, 0);
            foreach ($questionData as $qid => $consultTime)
            {
                $pipe->zAdd($cacheKey, [], $consultTime, $qid);
            }
            $pipe->exec();
        }
    }

    /**
     * 接单列表删除
     * @param string $qid
     * @throws \Exception
     */
    public function questionWaitingListDel(string $qid)
    {
        CacheManage::getInstance()->setCacheConfig($this->cacheModel)->delJudge($qid, 'waiting_list');
    }

    /**
     * 问答接单锁
     * @param string $qid
     * @return bool
     * @throws \Exception
     */
    public function astrReceivingLock(string $qid)
    {
        $cacheModel = CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('receiving_lock', $qid);
        $redis = $cacheModel->redisHandler;

        $res = $redis->setnx($cacheModel->cacheKey['receiving_lock'], 1);
        if ($res)
        {
            $redis->expire($cacheModel->cacheKey['receiving_lock'], 20);  // 20秒过期时间
        }

        return $res;
    }

    /**
     * 重写数据时获取数据
     * @param $ids
     * @param $type
     * @param $sortType
     * @return array|false|string
     */
    public function getInfoByIdsInData($ids, $type, $sortType)
    {
        try
        {
            if ($ids)
            {
                $model = self::withTrashed()->where('id', 'in', $ids);
            } else
            {
                $model = $this->where(['uid' => $type[0], 'status' => ['>', 0]]);
            }

            $data = $model
                ->order('create_time', 'DESC')
                ->column('id,uid,order_num,gid,question,question_des,question_imgs,question_type,is_anonymity,same_num,status,create_time,astr_receiving_time,astr_id,question_extend,is_synastry,read_num,comment_num,look_num,is_top,is_recommend_top,answer_duration,answer_content,reply_time,is_comment,discard_num,complain_status,consult_time,pay_time,success_time,extend,is_read,activity_discount,lock_reason,is_hide,delete_time,supplement_answer,supplement_answer_num,return_answer_num', 'id');
        }
        catch (\Exception $e)
        {
            $data = [];
        }

        return $data;
    }

    public function batchGetInfoByIds($cids, $field = [])
    {
        $resData = parent::batchGetInfoByIds($cids, $field);
        $this->dataInit($resData);
        return $resData;
    }

    /**
     * 数据初始化
     * @param array $resData
     * @return array
     */
    public function dataInit(array &$resData)
    {
        foreach ($resData as $orderId => $questionItemData)
        {
            $resData[$orderId] = arrayKeyData2int($questionItemData, ['status', 'uid', 'gid', 'success_time', 'pay_time', 'create_time', 'consult_time', 'complain_status', 'discard_num', 'is_comment', 'reply_time', 'answer_duration', 'astr_receiving_time', 'astr_id', 'is_recommend_top', 'is_top', 'look_num', 'comment_num', 'read_num', 'is_synastry', 'same_num', 'is_anonymity', 'question_type', 'is_read', 'is_hide', 'delete_time', 'supplement_answer_num', 'return_answer_num']);

            if (isset($questionItemData['supplement_answer']))
            {
                $resData[$orderId]['supplement_answer'] = $questionItemData['supplement_answer'] ? json_decode($questionItemData['supplement_answer'], true) : [];
            }

            if (isset($questionItemData['question_extend']))
            {
                $resData[$orderId]['question_extend'] = $questionItemData['question_extend'] ? json_decode($questionItemData['question_extend'], true) : [];
            }

            if (isset($questionItemData['question_imgs']))
            {
                $resData[$orderId]['question_imgs'] = $questionItemData['question_imgs'] ? json_decode($questionItemData['question_imgs'], true) : [];
            }
        }
    }

    /**
     * 获取问答首页 时间排序
     * @param int $uid
     * @param int $limit
     * @param array $excludeIds1 排除 之前已推荐
     * @param array $excludeIds2 排除 本次推荐
     * @return array|mixed
     * @throws \Exception
     */
    public function getQuestionTimeSortIds(int $uid, int $limit, array $excludeIds1 = [], array $excludeIds2 = [])
    {
        $resData = CacheManage::getInstance()
            ->setCacheConfig($this->cacheModel)
            ->setPage(-1)
            ->setSort('desc')
            ->getListPageDataIds(function ($isCache = true, $sortType = 'desc')
            {
                try
                {
                    $data = $this->where(['status' => ['in', [2, 4, 5, 6, 8]], 'is_hide' => 0])->order('consult_time ' . $sortType)->column('consult_time', 'id');
                    $resData = [];
                    foreach ($data as $id => $consultTime)
                    {
                        $resData[$id] = ['consult_time' => $consultTime];
                    }

                    return $resData;
                }
                catch (\Exception $e)
                {
                    return [];
                }
            }, 'consult_time', 0, 'time_sort');

        $resDataIds = array_keys($resData['data']);

        $ids = array_diff($resDataIds, $excludeIds1, $excludeIds2);

        $num = count($ids);

        if ($num < $limit)
        {
            $endNum = $limit - $num;

            $ids2 = array_diff($resDataIds, $ids, $excludeIds2);
            // 删除已经推荐的记录
            $this->delReadIdsCacheData($uid);
            if (count($ids2) <= $endNum)
            {
                return array_merge($ids, $ids2);
            } else
            {
                $ids3 = array_slice($ids2, 0, $endNum);
                return array_merge($ids, $ids3);
            }
        } elseif ($num === $limit)
        {
            return $ids;
        } else
        {
            return array_slice($ids, 0, $limit);
        }
    }

    /**
     * 获取问答首页 推荐值排序
     * @param $uid
     * @param int $limit
     * @param array $excludeIds1 排除 之前已推荐
     * @param array $excludeIds2 排除 本次推荐
     * @return array|mixed
     * @throws \Exception
     */
    public function getQuestionRecommendedSortIds($uid, int $limit, array $excludeIds1 = [], array $excludeIds2 = [])
    {
        $nowTime = time();
        $resData = CacheManage::getInstance()
            ->setCacheConfig($this->cacheModel)
            ->setPage(-1)
            ->getListPageDataIds(function ($isCache = true, $sortType = 'desc') use ($nowTime)
            {
                try
                {
                    $data = $this->where(['status' => ['in', [2, 4, 5, 6, 8]], 'is_hide' => 0])->column('consult_time,comment_num,same_num,read_num', 'id');
                    $rData = [];
                    foreach ($data as $id => $questionItem)
                    {
                        $recommendedNum = $questionItem['comment_num'] * 5 + $questionItem['same_num'] * 3 + $questionItem['read_num'] * 2;
                        $timeLong = $nowTime - $questionItem['consult_time'];
                        switch (true)
                        {
                            case $timeLong < 86400:
                                $recommendedNum = $recommendedNum / 1;
                                break;
                            case $timeLong < 172800: // 86400*2
                                $recommendedNum = $recommendedNum / 3;
                                break;
                            case $timeLong < 259200:// 86400*3
                                $recommendedNum = $recommendedNum / 7;
                                break;
                            case $timeLong < 518400:// 86400*6
                                $recommendedNum = $recommendedNum / 10;
                                break;
                            default:
                                // $recommendedNum = $recommendedNum / 15;
                                $recommendedNum = 0;
                        }

                        $rData[$id] = $recommendedNum;
                    }

                    if ($rData)
                    {
                        arsort($rData);
                    }
                    $resData = [];
                    foreach ($rData as $id => $resDatum)
                    {
                        $resData[$id] = ['recommended_num' => $resDatum];
                    }

                    return $resData;
                }
                catch (\Exception $e)
                {
                    return [];
                }
            }, 'recommended_num', 0, 'recommended_sort');

        $resDataIds = array_keys($resData['data']);

        $ids = array_diff($resDataIds, $excludeIds1, $excludeIds2);

        $num = count($ids);

        if ($num < $limit)
        {
            $endNum = $limit - $num;

            $ids2 = array_diff($resDataIds, $ids, $excludeIds2);
            // 删除已经推荐的记录
            $this->delReadIdsCacheData($uid);
            if (count($ids2) <= $endNum)
            {
                return array_merge($ids, $ids2);
            } else
            {
                $ids3 = array_slice($ids2, 0, $endNum);
                return array_merge($ids, $ids3);
            }
        } elseif ($num === $limit)
        {
            return $ids;
        } else
        {
            return array_slice($ids, 0, $limit);
        }
    }

    /**
     * 获取待接单列表
     * @param int $page
     * @param int $limit
     * @return array
     * @throws \Exception
     */
    public function getQuestionWaitingListIds(int $page, int $limit = 10)
    {
        $resData = CacheManage::getInstance()
            ->setCacheConfig($this->cacheModel)
            ->setPage($page)
            ->setPageSize($limit)
            ->setSort('asc')
            ->getListPageDataIds(function ($isCache = true, $sortType = 'desc')
            {
                try
                {
                    $data = $this->where(['status' => 2])->order('consult_time ' . $sortType)->column('consult_time', 'id');
                    $resData = [];
                    foreach ($data as $id => $consultTime)
                    {
                        $resData[$id] = ['consult_time' => $consultTime];
                    }

                    return $resData;
                }
                catch (\Exception $e)
                {
                    return [];
                }
            }, 'consult_time', 0, 'waiting_list');

        return $resData['data'] ? array_keys($resData['data']) : [];
    }

    /**
     * 更新问答问题 推荐值相关信息
     * @param array $questionInfo 问答问题信息
     *      [   问题信息内 需包含字段
     *          'id'    问题ID
     *          'read_num'  已读数 新增前
     *          'comment_num'   讨论数 新增前
     *          'same_num'  同问数 新增前
     *          'consult_time'  咨询时间
     *          'status'  问题状态
     *          'is_hide' 是否隐藏
     *      ]
     * @param int $changeType 更新类型 1=>已读数 2=>评论数 3=>同问数
     * @param int $inc 新增数
     * @throws \Exception
     */
    public function changeQuestionInfo(array $questionInfo, int $changeType, int $inc = 1): void
    {
        $cacheKey = 'question_answer:change_num:' . $questionInfo['id'];
        $num = Cache::inc($cacheKey);
        $changeTypeCacheKey = [
            1 => 'read_num',
            2 => 'comment_num',
            3 => 'same_num',
        ];
        // 更新缓存
        $questionInfo[$changeTypeCacheKey[$changeType]] = $questionInfo[$changeTypeCacheKey[$changeType]] + $inc;
        CacheManage::getInstance()->setCacheConfig($this->cacheModel, $questionInfo['id'])->setCache([$changeTypeCacheKey[$changeType] => $questionInfo[$changeTypeCacheKey[$changeType]]]);
        if (in_array($questionInfo['status'], [2, 4, 5, 6, 8], true))
        {   // 问题状态
            $recommendedNum = $questionInfo['comment_num'] * 5 + $questionInfo['same_num'] * 3 + $questionInfo['read_num'] * 2;
            $timeLong = time() - $questionInfo['consult_time'];
            switch (true)
            {
                case $timeLong < 86400:
                    $recommendedNum = $recommendedNum / 1;
                    break;
                case $timeLong < 172800: // 86400*2
                    $recommendedNum = $recommendedNum / 3;
                    break;
                case $timeLong < 259200:// 86400*3
                    $recommendedNum = $recommendedNum / 7;
                    break;
                case $timeLong < 518400:// 86400*6
                    $recommendedNum = $recommendedNum / 10;
                    break;
                default:
                    // $recommendedNum = $recommendedNum / 15;
                    $recommendedNum = 0;
            }

            if ($questionInfo['is_hide'] === 0 && ((isset($questionInfo['delete_time']) && $questionInfo['delete_time'] === 0) || !isset($questionInfo['delete_time'])))
            {   // 问题不隐藏
                CacheManage::getInstance()->setCacheConfig($this->cacheModel)->listAdd([$questionInfo['id'] => $recommendedNum], 0, 'recommended_sort');
            }
        }
        $updateStep = 1;    //更新数据库 频率
        if ($num >= $updateStep)
        {
            $this::withTrashed()->where(['id' => $questionInfo['id']])->update([
                'read_num' => $questionInfo['read_num'],
                'comment_num' => $questionInfo['comment_num'],
                'same_num' => $questionInfo['same_num'],
            ]);
            Cache::set($cacheKey, 0, 604800); //7天有效期
        }
    }

    /**
     * 获取 首页 推荐问答列表
     * @param int $uid
     * @param int $page
     * @param int $limit
     * @return array
     * @throws \Exception
     */
    public function getRecommentQids(int $uid, int $page, $limit = 10)
    {
        $nowTime = time();
        $resIds = [];
        $excludeIds = [];
        if ($uid)
        {
            request()->get(['page' => 1]);
            $pageData = $this->getListPage($uid, 'create_time', ['consult_time', 'question_type', 'is_hide', 'id', 'status'], 0, 'desc', 0);
            $id1 = 0;
            $id2 = 0;
            foreach ($pageData['data'] as $questionInfo)
            {
                if ($questionInfo['is_hide'])
                {
                    continue;
                }
                if ($id1 > 0 && $id2 > 0)
                {
                    break;
                }
                if ($nowTime - $questionInfo['consult_time'] < 86400 && in_array($questionInfo['status'], [2, 4, 5, 6, 8], false))
                {   // 发布时间在一小时内
                    if ($questionInfo['question_type'] > 0)
                    {   // 付费
                        if ($id1 === 0)
                        {
                            $id1 = $questionInfo['id'];
                            array_unshift($excludeIds, $id1);
                        }
                    } else
                    {
                        if ($id2 === 0)
                        {
                            $id2 = $questionInfo['id'];
                            $excludeIds[] = $id2;
                        }
                    }
                }
            }
        }
        // 获取后台强制置顶
        $topId = CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheType('string')->getDataAndSet(function ()
        {
            try
            {
                $id = $this->where(['status' => ['in', [2, 4, 5, 6, 8]], 'is_hide' => 0, 'is_top' => 1])->value('id');
                return $id ?: '-999';
            }
            catch (\Exception $e)
            {
                return '';
            }
        }, [], 'admin_recommended_top');

        if ($topId && $topId !== '-999')
        {
            $excludeIds[] = $topId;
        }

        if ($page === 1)
        {
            $resIds = $excludeIds;
        }
        $ids = $this->getAdminRecommentQids($uid, 2, $excludeIds);
        $resIds = array_merge($resIds, $ids);
        $excludeIds = array_merge($excludeIds, $ids);
        $oldRecommentIds = [];
        if ($uid)
        {
            // 获取之前已经推荐的问题 Ids
            $cacheModel = CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('questions_recommended_read', $uid);

            $oldRecommentIds = $cacheModel->redisHandler->zRange($cacheModel->cacheKey['questions_recommended_read'], 0, -1, false);
        }
        // 剩余推荐问题数
        $num = $limit - count($resIds);

        $num1 = 0;
        $num2 = 0;
        for ($i = 1; $i <= $num; $i++)
        {
            if (ceil($i / 3) % 2 === 0)
            {   // 第五优先级 获取数量
                $num2++;
            } else
            {   // 第四优先级
                $num1++;
            }
        }
        // 获取发布时间距离现在最近3条
        $ids1 = $num1 > 0 ? $this->getQuestionTimeSortIds($uid, $num1, $oldRecommentIds, $excludeIds) : [];
        $allIds = array_merge($excludeIds, $ids1);
        // 获取推荐值最高3条
        $ids2 = $num2 > 0 ? $this->getQuestionRecommendedSortIds($uid, $num2, $oldRecommentIds, $allIds) : [];
        $recommentIds = array_merge($ids1, $ids2);

        for ($i = 1; $i <= $num; $i++)
        {
            if (ceil($i / 3) % 2 === 0)
            {   // 第五优先级取数据
                if ($ids2)
                {
                    $resIds[] = (string)(array_shift($ids2));
                }
            } else
            {   // 第四优先级
                if ($ids1)
                {
                    $resIds[] = (string)(array_shift($ids1));
                }
            }
        }
        $this->setReadIds($uid, $recommentIds);

        return $resIds;
    }

    /**
     * 设置问答推荐 已推
     * @param int $uid
     * @param array $qids
     * @throws \Exception
     */
    public function setReadIds(int $uid, array $qids)
    {
        if ($uid)
        {
            $cacheModel = CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('questions_recommended_read', $uid);

            $redis = $cacheModel->redisHandler;
            $expire = 0;
            if (!$cacheModel->existsKey('questions_recommended_read'))
            {   // 首次 创建 设置过期时间 7天
                $expire = 604800;
            }

            foreach ($qids as $qid)
            {
                $redis->zAdd($cacheModel->cacheKey['questions_recommended_read'], [], $qid, $qid);
            }

            if ($expire > 0)
            {
                $redis->expire($cacheModel->cacheKey['questions_recommended_read'], $expire);
            }
        }
    }

    /**
     * 删除 问答推荐 已推 的缓存
     */
    public function delReadIdsCacheData(int $uid)
    {
        if ($uid && !$this->isDelUserReadQuestionRecord)
        {
            $this->isDelUserReadQuestionRecord = true;

            CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('questions_recommended_read', $uid)->rmCache('questions_recommended_read');
        }
    }

    /**
     * 获取后台推荐
     * @param int $uid
     * @param int $limit
     * @param array $excludeIds 排除的IDS
     * @return array
     * @throws \Exception
     */
    public function getAdminRecommentQids(int $uid, int $limit = 2, array $excludeIds = []): array
    {
        $resData = CacheManage::getInstance()
            ->setCacheConfig($this->cacheModel)
            ->setPage(-1)
            ->getListPageDataIds(function ($isCache = true, $sortType = 'desc')
            {
                try
                {
                    $data = $this->where(['status' => ['in', [2, 4, 5, 6, 8]], 'is_hide' => 0, 'is_recommend_top' => 1])->order('consult_time desc')->column('consult_time', 'id');
                    $resData = [];
                    foreach ($data as $id => $consultTime)
                    {
                        $resData[$id] = ['consult_time' => $consultTime];
                    }

                    return $resData;
                }
                catch (\Exception $e)
                {
                    return [];
                }
            }, 'consult_time', 0, 'admin_recommended');

        $resDataIds = array_keys($resData['data']);

        if ($uid)
        {
            $cacheModel = CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('admin_recommended_read', $uid);

            $range = $cacheModel->redisHandler->zRange($cacheModel->cacheKey['admin_recommended_read'], 0, -1, false);
        } else
        {
            $range = [];
        }

        $ids = array_diff($resDataIds, $range, $excludeIds);

        if (count($ids) <= $limit)
        {
            $this->setAdminRecommentReadIds($uid, $ids);
        } else
        {
            shuffle($ids);
            $ids = array_slice($ids, 0, $limit);
            $this->setAdminRecommentReadIds($uid, $ids);
        }

        return $ids;
    }

    /**
     * 设置后台推荐 已推
     * @param int $uid
     * @param array $qids
     * @throws \Exception
     */
    public function setAdminRecommentReadIds(int $uid, array $qids)
    {
        if ($uid)
        {
            $cacheModel = CacheManage::getInstance()->setCacheConfig($this->cacheModel)->setCacheKeyDetail('admin_recommended_read', $uid);

            $redis = $cacheModel->redisHandler;
            $expire = 0;
            if (!$cacheModel->existsKey('admin_recommended_read'))
            {   // 首次 创建 设置过期时间 7天
                $expire = 604800;
            }

            foreach ($qids as $qid)
            {
                $redis->zAdd($cacheModel->cacheKey['admin_recommended_read'], [], $qid, $qid);
            }

            if ($expire > 0)
            {
                $redis->expire($cacheModel->cacheKey['admin_recommended_read'], $expire);
            }
        }
    }

    /**
     * 获取首页展示的问答问题
     * @param int $uid 用户uid
     * @param int $page 当前页数
     * @param int $limit
     * @param bool $isGetUserAdorn 是否获取用户的装扮，默认不获取
     * @return array
     * @throws \app\common\lib\exception\ApiException
     */
    public function getIndexList(int $uid, int $page, int $limit = 10, bool $isGetUserAdorn = false)
    {
        $ids = $this->getRecommentQids($uid, $page, $limit);

        $questionListData = $this->batchGetInfoByIds($ids, ['status', 'id', 'uid', 'is_anonymity', 'is_hide', 'question_type', 'question_extend', 'consult_time', 'question', 'question_des', 'comment_num', 'read_num', 'question_imgs', 'same_num']);

        // 取 黑名单用户uid   ----------------------------------------------------------------
        $blacklistUids = (new AppBlacklist())->getBlacklistUids($uid);
        $userInfoList = [];
        $listData = [];
        $userVipModel = new ZlUserVip();
        $userVipLevelList = [];
        foreach ($questionListData as $listDatum)
        {
            if (!in_array($listDatum['status'], [2, 4, 5, 6, 8], true))
            {   // 状态异常 不显示
                continue;
            }
            if (in_array($listDatum['uid'], $blacklistUids, true))
            {
                continue;
            }
            if ($listDatum['is_hide'])
            {
                continue;
            }

            $userDes = '小行星神秘人';
            $nickname = '匿名用户';
            $avatar = '/test/question_answer/anonymity1.png';
            if ($listDatum['is_anonymity'] !== 1)
            {
                if (isset($userInfoList[$listDatum['uid']]))
                {
                    $userDes = $userInfoList[$listDatum['uid']]['user_des'];
                    $nickname = $userInfoList[$listDatum['uid']]['nickname'];
                    $avatar = $userInfoList[$listDatum['uid']]['avatar'];
                } else
                {
                    try
                    {
                        $userInfo = (new User())->getUserinfo(['id' => $listDatum['uid']]);
                    }
                    catch (\Exception $e)
                    {
                        continue;
                    }
                    if ($userInfo['rid'])
                    {
                        $recode = (new Recode())->getRecode(['id' => $userInfo['rid']]);
                        if ($recode)
                        {
                            $utilModel = new Util();
                            $userDes = '日' . $utilModel->recodeAstroShorthand($recode['sun']) . '月' . $utilModel->recodeAstroShorthand($recode['moon']) . '升' . $utilModel->recodeAstroShorthand($recode['asc']);
                        }
                    }
                    $nickname = $userInfo['nickname'];
                    $avatar = $userInfo['avatar'];
                    $userInfoList[$listDatum['uid']] = [
                        'nickname' => $nickname,
                        'avatar' => $avatar,
                        'user_des' => $userDes,
                    ];
                }
            }

            $sameInfo = (new Zlcr2UserSameQuestion())->getQuestionSameNumAndIsSame($uid, $listDatum['id']);
            $questionData = null;
            if (in_array($listDatum['question_type'], [2, 3], true))
            {
                $questionData = $listDatum['question_extend'];
            } else
            {
                $questionData = null;
            }
            if (isset($userVipLevelList[$listDatum['uid']]))
            {
                $vipLevel = $userVipLevelList[$listDatum['uid']];
            } else
            {
                $vipLevel = $userVipModel->getUserVipLevel($listDatum['uid']);
                $userVipLevelList[$listDatum['uid']] = $vipLevel;
            }

            $questionItem = [
                'nickname' => $nickname,
                'avatar' => $avatar,
                'same_num' => $listDatum['same_num'],
                'is_same' => $sameInfo['is_same'] ? 1 : 0,
                'create_time' => Util::timeToStr($listDatum['consult_time']),
                'user_des' => $userDes,
                'question' => $listDatum['question'],
                'question_des' => $listDatum['question_des'],
                'comment_num' => $listDatum['comment_num'],
                'view_num' => $listDatum['read_num'],
                'question_type' => $listDatum['question_type'],
                'qid' => (string)$listDatum['id'],
                'question_data' => $questionData,
                'photo_list' => $listDatum['question_imgs'],
                'isself' => $uid === $listDatum['uid'] ? 1 : 0,
                'vip_level' => $vipLevel,
            ];

            //设置头像框、标签、徽章（注意：匿名用户不显示 头像框、徽章、标签）
            if ($isGetUserAdorn && 1 !== (int)$listDatum['is_anonymity'])
            {
                $adorn = Util::getUserAdorn($listDatum['uid']);
                $listData[] = array_merge($questionItem, $adorn);
            } else
            {
                $listData[] = $questionItem;
            }


        }

        if ($page === 1 && count($listData) <= $limit)
        {
            return [
                'total' => count($listData),   // 总数
                'per_page' => $limit,   //每页显示数
                'current_page' => $page,    // 当前页数
                'last_page' => 1,    // 总页数
                'data' => $listData,
            ];
        } else
        {
            return [
                'total' => 10000,   // 总数
                'per_page' => $limit,   //每页显示数
                'current_page' => $page,    // 当前页数
                'last_page' => 1000,    // 总页数
                'data' => $listData,
            ];
        }
    }

    /**
     * 获取我的问答列表
     * @param int $uid
     * @param array $pageData
     * @param int $type 1=>我的问答 2=>  3=>我蹭看的
     * @return array
     * @throws \Exception
     */
    public function getMyQuestionList(int $uid, array $pageData, int $type): array
    {
        $resData = [];
        foreach ($pageData['data'] as $questionInfoItem)
        {
            $questionInfoItem['status'] = (int)$questionInfoItem['status'];
            switch ($questionInfoItem['status'])
            {
                case 1: // 待支付
                    $status = 5;
                    break;
                case 2: // 已支付待接单
                    $status = 0;
                    break;
                case 4: // 待解答
                    $status = 1;
                    break;
                case 5: // 已解答
                case 20: // 退回重答
                    $status = 2;
                    if (count((new Zlcr2UserAddQuestion())->getQuestionAddQuestionInfo($questionInfoItem['id'])) > 0)
                    {
                        $status = 3;
                    }
                    break;
                case 6: // 已完成
                case 7: // 用户申述且已通过完成
                case 21: // 已完成且收益扣除【占星师放弃重答】
                    $status = 4;
                    break;
                case 8: // 追问待解答
                    $status = 3;
                    break;
                case 9: // 占星师弃答3次取消并退款
                case 11: // 接单超时已取消订单
                case 3: // 未支付已取消
                case 10: // 用户支付后主动取消并退款
                    if ($questionInfoItem['status'] === 9)
                    {
                        $cannelReason = '问题无法回答';
                    } elseif ($questionInfoItem['status'] === 11)
                    {
                        $cannelReason = '无咨询师接单';
                    }
                    $status = 6;
                    break;
            }

            $qid = $questionInfoItem['qid'] ?? $questionInfoItem['id'];

            $target = 'local';
            $link = $questionInfoItem['status'] === 3 ? 'empty' : "question_detail?qid={$qid}&comment_id=0&need_auth=0";
            if ($type === 2 && $questionInfoItem['delete_time'] > 0)
            {
                $target = 'toast';
                $link = '该问答已删除';
            }

            $resData[] = [
                'id' => (string)$questionInfoItem['id'],
                'qid' => $qid,
                'question' => $questionInfoItem['question'],
                'question_type' => (int)$questionInfoItem['question_type'],
                'status' => $status ?? 0,
                'create_time' => Util::timeToStr($questionInfoItem['create_time']),
                'view_num' => (int)$questionInfoItem['read_num'],   // 浏览数
                'comment_num' => (int)$questionInfoItem['comment_num'], // 评论数
                'is_reply' => $questionInfoItem['is_read'] ? 0 : 1, // 是否有新回复
                'is_cannel' => (int)$questionInfoItem['status'] === 2 ? 1 : 0,  // 能否取消
                'cannel_reason' => $cannelReason ?? '',  // 取消原因
                'order_num' => $questionInfoItem['order_num'] ?? '',
                'target' => $target,
                'link' => $link,
            ];
        }

        $pageData['data'] = $resData;
        $ids1 = $this->getUserUnReadIds($uid);//未读问题ids
        $pageData['num_list'][] = count($ids1);
        $pageData['num_list'][] = 0;//我讨论的未读数
        $ids3 = (new Zlcr2QuestionUserView())->getUserUnReadViewIds($uid);//未读蹭看ids
        $pageData['num_list'][] = count($ids3);
        return $pageData;
    }

    /**
     * 获取问答 用户未读蹭看ids
     * @param int $uid
     * @return array
     * @throws \Exception
     */
    public function getUserUnReadIds(int $uid): array
    {
        $resData = CacheManage::getInstance()
            ->setCacheConfig($this->cacheModel)
            ->setCacheKeyDetail('unread_question', $uid)
            ->setPage(-1)
            ->getListPageDataIds(function ($isCache = true, $sortType = 'desc') use ($uid)
            {
                try
                {
                    $data = $this->where(['uid' => $uid, 'is_read' => 0, 'status' => ['>', 0]])->column('id');
                    $resData = [];
                    foreach ($data as $id)
                    {
                        $resData[$id] = ['id' => $id];
                    }

                    return $resData;
                }
                catch (\Exception $e)
                {
                    return [];
                }
            }, 'id', 0, 'unread_question');

        return $resData['data'] ? array_keys($resData['data']) : [];
    }

    /**
     * 获取本单问题的所有收益 和 用户本单实际支付总金额
     * @param array $questionInfo ['astr_id','id','order_num']
     * @param array $taskInfo ['qa_level','create_time'=>接单时间]
     * @return array
     * @throws \Exception
     */
    public function getQuestionEarning(array $questionInfo, array $taskInfo)
    {
        $goodInfo = Util::getZhunleQuestionAnswerConfig();

        $astrModel = new ZlcrAstr();

        $oldPrice = (float)(sprintf('%.2f', $goodInfo[$questionInfo['gid']]['price'] * $astrModel->getAstrQuestionAnswerProportion($taskInfo['create_time'], $questionInfo['question_type'], $taskInfo['qa_level'])));
        // 问题价格
        $questionPrice = (float)(sprintf("%.2f", $oldPrice * $questionInfo['activity_discount']));
        $addQuestionLists = (new Zlcr2UserAddQuestion())->getQuestionAddQuestionInfo($questionInfo['id']);

        // 问题支付金额
        $orderModel = new Orders();
        $orderInfo = $orderModel->getInfoById($questionInfo['order_num']);
        $totalAmount = $orderInfo['total_amount'];

        // 计算咨询师 追问回复收益
        $addQuestionOldPrice = $goodInfo[$questionInfo['gid']]['add_price'] * $astrModel->getAstrQuestionAnswerAddQuestionProportion($taskInfo['create_time'], $questionInfo['question_type'], $taskInfo['qa_level']);
        $addQuestionPrice = 0;
        foreach ($addQuestionLists as $addQuestionItem)
        {
            if ($addQuestionItem['status'] === 4 && $addQuestionItem['reply_type'] === 1)
            {   //  状态 1=>待支付  2=>待解答 3=>未支付已关闭 4=>已完成 5=>占星师申述已取消  6=>追问回复超时已取消
                $addQuestionPrice += $addQuestionOldPrice * $addQuestionItem['activity_discount'];
                if ($addQuestionItem['order_num'])
                {
                    $orderInfo = $orderModel->getInfoById($addQuestionItem['order_num']);
                    $totalAmount += $orderInfo['total_amount'];
                }
            }
        }
        // 问题 + 追问 的总收益
        $totalPrice = (float)(sprintf("%.2f", $questionPrice + $addQuestionPrice));
        $totalAmount = (float)(sprintf("%.2f", $totalAmount));
        // 给收益扣税
        $earnings = Util::getAfterTaxAmount($totalPrice);

        return [
            'earning' => $earnings,
            'total_amount' => $totalAmount,
        ];
    }

    /**
     * 获取本单问题的所有收益包括追问待回答   仅进行中列表使用
     * @param array $questionInfo ['astr_id','id','order_num']
     * @param array $taskInfo ['qa_level']
     * @return float
     * @throws \Exception
     */
    public function getQuestionEarning2(array $questionInfo, array $taskInfo)
    {
        $goodInfo = Util::getZhunleQuestionAnswerConfig();
        $astrModel = new ZlcrAstr();

        $oldPrice = (float)(sprintf('%.2f', $goodInfo[$questionInfo['gid']]['price'] * $astrModel->getAstrQuestionAnswerProportion($taskInfo['create_time'], $questionInfo['question_type'], $taskInfo['qa_level'])));
        // 问题价格
        $questionPrice = (float)(sprintf("%.2f", $oldPrice * $questionInfo['activity_discount']));
        $addQuestionLists = (new Zlcr2UserAddQuestion())->getQuestionAddQuestionInfo($questionInfo['id']);

        // 计算咨询师 追问回复收益
        $addQuestionOldPrice = $goodInfo[$questionInfo['gid']]['add_price'] * $astrModel->getAstrQuestionAnswerAddQuestionProportion($taskInfo['create_time'], $questionInfo['question_type'], $taskInfo['qa_level']);
        $addQuestionPrice = 0;
        foreach ($addQuestionLists as $addQuestionItem)
        {
            if (in_array($addQuestionItem['status'], [2, 4], true))
            {   //  状态 1=>待支付  2=>待解答 3=>未支付已关闭 4=>已完成 5=>占星师申述已取消  6=>追问回复超时已取消
                $addQuestionPrice += $addQuestionOldPrice * $addQuestionItem['activity_discount'];
            }
        }
        // 问题 + 追问 的总收益
        $totalPrice = (float)(sprintf("%.2f", $questionPrice + $addQuestionPrice));

        return Util::getAfterTaxAmount($totalPrice);
    }

    /**
     * 获取占星师 追问回复 预估收益 不参与活动折扣收益
     * @param int $gid 问答商品ID
     * @param int $astrlevel 当前问答类型咨询师等级
     * @param int $astrReceivingTime 占星师接单时间
     * @return float
     * @throws \Exception
     */
    public function getAddquestionEarning(int $gid, int $astrlevel, int $astrReceivingTime)
    {
        $goodInfo = Util::getZhunleQuestionAnswerConfig();
        $astrModel = new ZlcrAstr();
        // 计算咨询师 追问回复收益
        $addQuestionOldPrice = $goodInfo[$gid]['add_price'] * $astrModel->getAstrQuestionAnswerAddQuestionProportion($astrReceivingTime, $goodInfo[$gid]['type'], $astrlevel);

        return Util::getAfterTaxAmount(sprintf("%.2f", $addQuestionOldPrice));  // 预估收益 扣除营业税费及手续费
    }

    /**
     * 通过问题ID和占星师ID 获取 占星师任务ID
     * @param string $qid
     * @param int $astrId
     * @return float|mixed|string
     */
    public function getTaskIdByQidAndAstrd(string $qid, int $astrId)
    {
        return (new Zlcr2AstrTasks())->where(['astr_id' => $astrId, 'qid' => $qid])->value('id');
    }
}
